package cn.zzq.aix.nativeinterface.javaplay;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.HashMap;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.annotations.UsesLibraries;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.Form;
import com.google.appinventor.components.runtime.collect.Maps;
import com.google.appinventor.components.runtime.util.FileUtil;
import com.google.appinventor.components.runtime.util.MediaUtil;
import com.google.appinventor.components.runtime.util.YailList;
import com.google.appinventor.components.runtime.util.YailProcedure;
import com.google.appinventor.components.runtime.util.YailProcedure.Executable;

import android.content.Context;
import android.os.Environment;
import bsh.BshClassManager;
import bsh.BshMethod;
import bsh.EvalError;
import bsh.Interpreter;
import cn.zzq.aix.nativeinterface.javareflector.NumberUtil;
import cn.zzq.aix.nativeinterface.javareflector.ReflectException;
import cn.zzq.aix.nativeinterface.javareflector.Util;
import dalvik.system.DexClassLoader;
import gnu.math.Complex;

@UsesLibraries(libraries = "bsh-2.0b4.jar")
@SimpleObject(external = true)
@DesignerComponent(//
		description = "luancher相关组件", //
		iconName = "images/extension.png", //
		nonVisible = true, //
		category = ComponentCategory.EXTENSION, //
		version = 1) //
public class JavaPlay extends AndroidNonvisibleComponent {
	Interpreter interpreter;
	private HashMap<Integer, YailProcedure> methodNameSpace = Maps.newHashMap();

	public JavaPlay(ComponentContainer container) {
		super(container == null ? null : container.$form());
		interpreter = new Interpreter();
		SetObject("methodNameSpace", methodNameSpace);
	}

	@SimpleFunction(description = "导入类，以便于通过简称访问该类或创建对象，若类简称发生重复，将用后一个类覆盖前一个类")
	public void ImportClass(String className) {
		interpreter.getNameSpace().importClass(className);
	}

	@SimpleFunction(description = "导入包")
	public void ImportPackage(String packageName) {
		interpreter.getNameSpace().importPackage(packageName);
	}

	@SimpleFunction(description = "执行一段java代码，可以定义java方法，" + "调用java方法，"//
			+ "计算一段表达式，"//
			+ "获取一个变量值，"//
			+ "定义变量，"//
			+ "创建匿名接口，"//
			+ "创建对象等"//
			+ "因Android系统限制，无法创建Java类") //
	public Object Evalute(String code) {
		try {
			return interpreter.eval(code);
		} catch (EvalError e) {
			e.printStackTrace();
			throw new ReflectException(code, "Evalute", e);
		}
	}

	@SimpleFunction(description = "获取当前Java解释器引擎中的变量的值")
	public Object Get(String name) {
		try {
			return interpreter.get(name);
		} catch (EvalError e) {
			e.printStackTrace();
			throw new ReflectException(name, "Get", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetInt(String name, int value) {
		try {
			interpreter.set(name, value);
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetInt", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetLong(String name, long value) {
		try {
			interpreter.set(name, value);
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetLong", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetShort(String name, short value) {
		try {
			interpreter.eval("short " + name + "=" + value + ";");
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetShort", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetByte(String name, byte value) {
		try {
			interpreter.eval("byte " + name + "=" + value + ";");
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetByte", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetDouble(String name, double value) {
		try {
			interpreter.set(name, value);
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetDouble", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetFloat(String name, float value) {
		try {
			interpreter.set(name, value);
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetFloat", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetBoolean(String name, boolean value) {
		try {
			interpreter.set(name, value);
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetBoolean", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetChar(String name, Object charData) {
		try {
			interpreter.eval("char " + name + "=" + "'" + Util.buildChar(charData) + "';");
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetChar", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetNull(String name) {
		try {
			interpreter.set(name, null);
		} catch (EvalError e) {

			e.printStackTrace();
			throw new ReflectException(name, "SetNull", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void SetObject(String name, Object value) {
		try {
			interpreter.set(name, value);
		} catch (EvalError e) {
			e.printStackTrace();
			throw new ReflectException(new Object[] { name, value }, "SetObject", e);
		}
	}

	@SimpleFunction(description = "按照当前类型设置当前Java解释器引擎中指定变量的值")
	public void Set(String name, Object type, Object value) {
		try {
			interpreter.set(name,
					value instanceof Complex ? NumberUtil.AINumber2JavaNumber((Complex) value, (Type) type) : value);
		} catch (EvalError e) {
			e.printStackTrace();
			throw new ReflectException(new Object[] { name, type, value }, "Set", e);

		}
	}

	@SimpleFunction(description = "获取当前Java解释器引擎中的所有变量名")
	public YailList GetVariableNames() {
		String[] variableNames = interpreter.getNameSpace().getVariableNames();
		return YailList.makeList(variableNames);
	}

	@SimpleFunction(description = "获取当前Java解释器引擎中的所有方法名,重载方法只显示一次")
	public YailList GetMethodNames() {
		String[] methodNames = interpreter.getNameSpace().getMethodNames();
		return YailList.makeList(methodNames);
	}

	@SimpleFunction(description = "获取当前Java解释器引擎中的所有方法名和变量名")
	public YailList GetAllNames() {
		String[] allNames = interpreter.getNameSpace().getAllNames();
		return YailList.makeList(allNames);
	}

	@SimpleFunction(description = "删除当前Java解释器引擎中指定变量名的变量")
	public void RemoveVariable(String name) {
		interpreter.getNameSpace().unsetVariable(name);
	}

	@SimpleFunction(description = "向当前Java解释器引擎中添加一个方法，"//
			+ "该方法将绑定ai的一个匿名过程，"//
			+ "当调用此java方法时，将自动去调用这个匿名过程") //
	public void AddMethod(String name, YailProcedure function) {
		methodNameSpace.put(function.hashCode(), function);
		StringBuffer sb = new StringBuffer("public Object " + name + "(");
		for (int i = 0; i < function.numArgs(); i++) {
			sb.append("Object arg" + i + ",");
		}
		sb.deleteCharAt(sb.length() - 1);
		sb.append("){return ");
		sb.append("methodNameSpace.get(" + function.hashCode() + ").call(new Object[]{");
		for (int i = 0; i < function.numArgs(); i++) {
			sb.append("arg" + i + ",");
		}
		sb.deleteCharAt(sb.length() - 1);
		sb.append("});");
		sb.append("}");
		String methodDeclare = sb.toString();
		System.out.println(methodDeclare);
		Evalute(methodDeclare);
	}

	private BshMethod getFIrstMethodByName(String name) {
		for (BshMethod method : interpreter.getNameSpace().getMethods()) {
			if (method.getName().equals(name)) {
				return method;
			}
		}
		return null;
	}
	@SimpleFunction(description = "获取一个java方法，"//
			+ "并以ai匿名函数的形式返回，当调用此匿名函数时，"//
			+ "将自动调用java解释器内部的该方法") //
	public YailProcedure GetMethod(String name) {
		try {
			final BshMethod method=getFIrstMethodByName(name);
			if(method==null) {
				throw new ReflectException(name, "GetMethod","不存在的方法");
			}

			final Interpreter mInterpreter = interpreter;
			return new YailProcedure(new Executable() {

				@Override
				public int numArgs() {
					int num = method.getParameterTypes().length;
					return num;
				}

				@Override
				public Object execute(Object... args) {
					try {
						return method.invoke(args, mInterpreter);
					} catch (EvalError e) {
						e.printStackTrace();
						throw new ReflectException(new Object[] { method, args }, "GetMethod", e);
					}
				}
			});
		} catch (Exception e1) {
			e1.printStackTrace();
			throw new ReflectException(new Object[] { name }, "GetMethod", e1);
		}

	}
	
	@SimpleFunction(description = "将除素材外的ai路径转换为java中可用的绝对路径")
	public static String ToAbsolutePath(String path) {
		if (path.startsWith("/sdcard")) {
			path = Environment.getExternalStorageDirectory().getAbsolutePath() + path.substring(7);
		} else if (path.startsWith("~/")) {
			path = Form.getActiveForm().getFilesDir() + path.substring(1);
		} else if (path.startsWith("//")) {
			// 素材文件
			throw new ReflectException(path, "ToAbsolutePath", "无法获取素材文件的文件路径");
		} else if (!path.startsWith("/")) {
			throw new ReflectException(path, "ToAbsolutePath", "不合法的文件路径");
		}
		try {
			return new File(path).getCanonicalPath();
		} catch (IOException e) {
			throw new ReflectException(path, "ToAbsolutePath", e, "发生io异常");
		}
	}

	@SimpleFunction(description = "清空应用程序的dex文件缓存")
	public void ClearDexCache() {
		File dexOutput = Form.getActiveForm().getDir("dexes", Context.MODE_PRIVATE);
		for (File dexFile : dexOutput.listFiles()) {
			Util.deleteFile(dexFile);
		}
	}

	@SimpleFunction(description = "清空应用程序的so文件缓存")
	public void ClearSoCache() {
		File dexOutput = Form.getActiveForm().getDir("so", Context.MODE_PRIVATE);
		for (File dexFile : dexOutput.listFiles()) {
			Util.deleteFile(dexFile);
		}
	}
	

	
	@SimpleProperty(description = "设置当前java解释器环境的ClassLoader")
	public void CurrentClassLoader(Object classLoader) {
		interpreter.setClassLoader((ClassLoader) classLoader);
	}

	@SimpleProperty(description = "获取当前java解释器环境的ClassLoader")
	public Object CurrentClassLoader() {
		try {
			BshClassManager classManager = interpreter.getNameSpace().getClassManager();
			Field field = BshClassManager.class.getDeclaredField("externalClassLoader");
			field.setAccessible(true);
			return field.get(classManager);
		} catch (Exception e) {
			throw new ReflectException(null, "GetClassLoader", e);
		}
	}

}
